﻿namespace VividKit.Controls
{
	using System;
	using System.Collections.Generic;
	using System.ComponentModel;
	using System.Linq;
	using System.Windows.Controls;
	using System.Windows.Navigation;
	using Microsoft.Phone.Controls;
	using VividKit.PresentationModel.Navigation;

	/// <summary>
	/// Represents a page that associated with a <see cref="T:NavigableViewModel"/>.
	/// </summary>
	public class NavigablePage : PhoneApplicationPage
	{
		private bool isNewInstance;

		/// <summary>
		/// Initializes a new instance of the <see cref="NavigablePage"/> class.
		/// </summary>
		public NavigablePage()
		{
			this.isNewInstance = true;
		}

		/// <summary>
		/// This method is called when the hardware Back button is pressed.
		/// </summary>
		/// <param name="e">Set e.Cancel to true to indicate that the request was handled by the application.</param>
		protected override void OnBackKeyPress(CancelEventArgs e)
		{
			var navigator = this.DataContext as NavigableViewModel;
			if (navigator != null)
			{
				navigator.RaiseBackKeyPress(e);
			}
		}

		/// <summary>
		/// Called when a page is no longer the active page in a frame.
		/// </summary>
		/// <param name="e">An object that contains the event data.</param>
		protected override void OnNavigatedFrom(NavigationEventArgs e)
		{
			var navigator = this.DataContext as INavigable;
			if (navigator != null)
			{
				if (e.NavigationMode != NavigationMode.Back)
				{
					HandleSerializing(navigator);
				}

				navigator.OnNavigatedFrom(null);
			}
		}

		/// <summary>
		/// Called when a page becomes the active page in a frame.
		/// </summary>
		/// <param name="e">An object that contains the event data.</param>
		protected override void OnNavigatedTo(NavigationEventArgs e)
		{
			var navigator = this.DataContext as INavigable;
			if (navigator != null)
			{
				navigator.OnNavigatedTo(e.NavigationMode == NavigationMode.Back);

				if (this.isNewInstance == false || HandleDeserializing(navigator) == false)
				{
					var tombstone = navigator as ITombstone;
					if (tombstone != null)
					{
						IDictionary<string, object> state = null;

						var page = e.Content as Page;
						if (page != null && page.NavigationContext.QueryString.Any())
						{
							state = page.NavigationContext.QueryString.ToDictionary(p => p.Key, p => (object)p.Value);
						}
						else
						{
							var parameter = NavigatorService.GetExtraData(this);
							if (parameter != null)
							{
								state = new Dictionary<string, object>
								{
									{ String.Empty, parameter }
								};
							}
						}

						tombstone.OnDeserializing(state ?? new Dictionary<string, object>());
					}
				}
			}

			this.isNewInstance = false;
		}

		/// <summary>
		/// Handles the page deserializing.
		/// </summary>
		/// <param name="navigator">The navigator view model.</param>
		private bool HandleDeserializing(INavigable navigator)
		{
			var tombstone = navigator as ITombstone;
			if (tombstone != null)
			{
				var hasState = this.State.Any();

				if (hasState)
				{
					tombstone.OnDeserializing(this.State);
				}

				return hasState;
			}

			return false;
		}

		/// <summary>
		/// Handles the page serializing.
		/// </summary>
		/// <param name="navigator">The navigator view model.</param>
		private void HandleSerializing(INavigable navigator)
		{
			var tombstone = navigator as ITombstone;
			if (tombstone != null)
			{
				tombstone.OnSerializing(this.State);
			}
		}
	}
}